{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "6330589b-a6a3-4e57-ab26-de318a033bb4",
   "metadata": {},
   "source": [
    "# 线性回归回顾\n",
    "假设输出与输入具有如下的线性关系：\n",
    "$$y = wx + b$$  \n",
    "损失函数：\n",
    "$$MSE = \\frac{1}{n}\\sum^n_{i=1}(y_i - \\hat{y_i})^2$$  \n",
    "计算损失函数的梯度，按照下面的公式更新：  \n",
    "$$w = w - \\alpha\\frac{\\partial L}{\\partial w}$$  \n",
    "$$b = b - \\alpha\\frac{\\partial L}{\\partial b}$$  \n",
    "其中，L是损失函数，$\\alpha$是学习率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "f95b4fa3-ba20-498b-9db5-e21abfd72bc2",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import torch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "101a5987-dbb4-42a5-b3b1-6a55c57502ad",
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "15eb04c6-c872-4eb3-9525-91e6f1b8b9e3",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.random.rand(100, 1)\n",
    "y = 1 + 2 * x + 0.1 * np.random.randn(100, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "03b40725-fdbf-496f-b116-96afca1a0e9a",
   "metadata": {},
   "outputs": [],
   "source": [
    "x_tensor = torch.from_numpy(x).float()\n",
    "y_tensor = torch.from_numpy(y).float()\n",
    "# tensor是张量的意思，以一种多维数组。在机器学习领域，tensor通常用来表示训练数据，模型参数，输入数据等"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7be437eb-d8df-42c7-a556-8603c32a5436",
   "metadata": {},
   "source": [
    "### 设置超参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "3a0acd54-fbf6-4434-866c-8894f9bdf00e",
   "metadata": {},
   "outputs": [],
   "source": [
    "learning_rate = 0.1 # 学习率\n",
    "num_epochs = 1000 # 迭代次数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21ec4c84-a9b3-4f00-b372-929ebb29dc9f",
   "metadata": {},
   "source": [
    "### 初始化参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "d6d981ca-2759-48f0-bd18-68cda9c08fd1",
   "metadata": {},
   "outputs": [],
   "source": [
    "w = torch.randn(1, requires_grad=True) # 均值为0，标准差为1的随机张量\n",
    "b = torch.randn(1, requires_grad=True)\n",
    "# 希望在反向传播的时候计算梯度"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b0356aa-3462-4419-bfc0-77be13b79da5",
   "metadata": {},
   "source": [
    "### 开始训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "168f544f-c2f6-43ba-96d3-5387eaa315eb",
   "metadata": {},
   "outputs": [],
   "source": [
    "for epoch in range(num_epochs):\n",
    "    # 计算预测值\n",
    "    y_pred = x_tensor * w + b\n",
    "\n",
    "    # 计算损失\n",
    "    loss = ((y_pred - y_tensor) ** 2).mean()\n",
    "\n",
    "    # 反向传播\n",
    "    loss.backward()\n",
    "\n",
    "    # 更新参数\n",
    "    with torch.no_grad():\n",
    "        w -= learning_rate * w.grad\n",
    "        b -= learning_rate * b.grad\n",
    "\n",
    "        # 清空梯度\n",
    "        w.grad.zero_()\n",
    "        b.grad.zero_()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "33e368cc-a059-4f0c-976c-ec640839ae2a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([1.9540], requires_grad=True), tensor([1.0215], requires_grad=True))"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w, b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b1b1fe00-2f6c-45fa-a2df-4a2c9b01e492",
   "metadata": {},
   "source": [
    "### 可视化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "31e08c77-e76a-44fd-9f41-ddc401d024c3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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ezZs2KCRI0eqtLRUp5xyihYtWpScizHy0JIlS4ySkhLjN7/5jfH6668b119/vTFgwABjz549lue/8MILRnFxsfGTn/zEaGxsNL7//e8bffv2NV577bU0X3lucnu/p0yZYjzwwAPG1q1bje3btxvXXHON4fP5jH/+859pvvLc4/Zem5qamowTTjjB+PznP29MmjQpPRebB9ze7/b2duNzn/ucccUVVxibNm0ympqajA0bNhgNDQ1pvvLc5PZ+P/7440Zpaanx+OOPG01NTcbTTz9tVFZWGrNnz07zleemNWvWGHfccYexdOlSQ5KxbNmyqOfv3LnT6N+/v3HrrbcajY2Nxi9/+UujuLjYWLt2bcLXkpdhZNSoUcasWbNCv3d2dhqDBw82FixYYHn+1772NWPChAlhx8477zzjm9/8ZkqvM1+4vd+9HT582CgrKzP+53/+J1WXmDfiudeHDx82LrjgAuORRx4xZsyYQRhxwe39XrhwoXHyyScbH3/8cbouMa+4vd+zZs0yLr300rBjt956qzF69OiUXmc+chJGvvvd7xpnnHFG2LErr7zSuOyyyxL+/rybpvn444/16quvauzYsaFjRUVFGjt2rOrr6y3fU19fH3a+JF122WW25+OoeO53b4cOHVJHR4cqKipSdZl5Id57fdddd2ngwIG69tpr03GZeSOe+/3UU0+ppqZGs2bN0qBBgzR8+HD9+Mc/VmdnZ7ouO2fFc78vuOACvfrqq6GpnJ07d2rNmjW64oor0nLNhSaVz8qc2CjPjffff1+dnZ0aNGhQ2PFBgwbpjTfesHxPa2ur5fmtra0pu858Ec/97u22227T4MGDI/4lR7h47vWmTZv06KOPqqGhIQ1XmF/iud87d+7U+vXrdfXVV2vNmjV6++23deONN6qjo0Nz585Nx2XnrHju95QpU/T+++/rwgsvlGEYOnz4sL71rW/p9ttvT8clFxy7Z2VbW5s++ugj9evXL+7PzruREeSWu+++W0uWLNGyZcvk9XozfTl55cCBA5o2bZoefvhhHX/88Zm+nILQ1dWlgQMH6qGHHtI555yjK6+8UnfccYcefPDBTF9aXtqwYYN+/OMf61e/+pW2bNmipUuXavXq1Zo/f36mLw0u5d3IyPHHH6/i4mLt2bMn7PiePXvk9/st3+P3+12dj6Piud+m++67T3fffbeeffZZnXXWWam8zLzg9l7v2LFDzc3NmjhxYuhYV1eXJKlPnz568803NWzYsNRedA6L59/tyspK9e3bV8XFxaFjn/nMZ9Ta2qqPP/5YJSUlKb3mXBbP/b7zzjs1bdo0XXfddZKkM888UwcPHtQNN9ygO+64Q0VF/Pd2Mtk9K8vLyxMaFZHycGSkpKRE55xzjp577rnQsa6uLj333HOqqamxfE9NTU3Y+ZK0bt062/NxVDz3W5J+8pOfaP78+Vq7dq0+97nPpeNSc57be3366afrtddeU0NDQ+jny1/+si655BI1NDRoyJAh6bz8nBPPv9ujR4/W22+/HQp9kvTWW2+psrKSIBJDPPf70KFDEYHDDIIG264lXUqflQkvgc1CS5YsMUpLS41FixYZjY2Nxg033GAMGDDAaG1tNQzDMKZNm2Z873vfC53/wgsvGH369DHuu+8+Y/v27cbcuXMp7XXB7f2+++67jZKSEuMPf/iD0dLSEvo5cOBApv6EnOH2XvdGNY07bu/3O++8Y5SVlRk33XST8eabbxqrVq0yBg4caPzwhz/M1J+QU9ze77lz5xplZWXGE088YezcudN45plnjGHDhhlf+9rXMvUn5JQDBw4YW7duNbZu3WpIMn76058aW7duNf7xj38YhmEY3/ve94xp06aFzjdLe7/zne8Y27dvNx544AFKe2P55S9/aZx00klGSUmJMWrUKOOll14KvTZmzBhjxowZYef//ve/Nz796U8bJSUlxhlnnGGsXr06zVec29zc70996lOGpIifuXPnpv/Cc5Dbf7d7Ioy45/Z+v/jii8Z5551nlJaWGieffLLxox/9yDh8+HCarzp3ubnfHR0dRm1trTFs2DDD6/UaQ4YMMW688Ubjgw8+SP+F56A//elPlv9bbN7jGTNmGGPGjIl4z4gRI4ySkhLj5JNPNh577LGkXIvHMBjLAgAAmZN3a0YAAEBuIYwAAICMIowAAICMIowAAICMIowAAICMIowAAICMIowAAICMIowAAICMIowAAICMIowAAICMIowAAICMIowAAICM+v8Bk6/KWxDsRDsAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.plot(x, y, 'o')\n",
    "plt.plot(x_tensor.numpy(), y_pred.detach().numpy())\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "31c9f927-bf9a-4d9b-8438-ee4c6b286226",
   "metadata": {},
   "source": [
    "### 使用pytorch实现：本质上就是只有一个Linear层"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "a488bbd2-4bd4-4db4-aace-9dd1955cd64e",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import torch\n",
    "import torch.nn as nn"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "6833c4c5-238f-4b59-af1c-726f112d78f0",
   "metadata": {},
   "outputs": [],
   "source": [
    "input_dim = 1\n",
    "output_dim = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "e16d592a-ba1c-40ff-b633-4c2abd6693b7",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = nn.Linear(input_dim, output_dim)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "3f61fe76-be59-44cc-8d46-d2b6194cbd2e",
   "metadata": {},
   "outputs": [],
   "source": [
    "criterion = nn.MSELoss()\n",
    "optimizer = torch.optim.SGD(model.parameters(), lr=0.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "d5afe9b3-2752-40a4-92d2-73b707db533d",
   "metadata": {},
   "outputs": [],
   "source": [
    "for epoch in range(num_epochs):\n",
    "    y_pred = model(x_tensor)\n",
    "    loss = criterion(y_pred, y_tensor)\n",
    "\n",
    "    optimizer.zero_grad()\n",
    "\n",
    "    loss.backward()\n",
    "\n",
    "    optimizer.step()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "9e2cea5f-2464-4c7f-b3bd-4dcbf2387800",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([1.9540], requires_grad=True), tensor([1.0215], requires_grad=True))"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w, b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "129dd419-bf46-45fd-8a70-066e51eef508",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.21"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
